{- This file is part of funbot.
 -
 - Written in 2015, 2016, 2017 by fr33domlover <fr33domlover@riseup.net>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

{-# LANGUAGE OverloadedStrings #-}

module FunBot.Settings.Sections.Shortcuts
    ( shortcutSec
    , addShortcut
    , deleteShortcut
    )
where

import Control.Monad (unless)
import Control.Monad.Trans.Class (lift)
import Data.Bool (bool)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Settings.Section hiding (delete)
import Data.Settings.Types
import Database.Persist
import Network.IRC.Fun.Bot.IrcLog
import Network.IRC.Fun.Bot.MsgCount
import Network.IRC.Fun.Bot.Nicks
import Network.IRC.Fun.Bot.State
import Network.IRC.Fun.Types.Base (Channel (..), Nickname (..))

import qualified Data.CaseInsensitive as CI
import qualified Data.HashMap.Lazy as M
import qualified Data.Text as T

import FunBot.Model
import FunBot.Settings.MkOption
import FunBot.Types
import FunBot.Util

-- | Create a settings section for a shortcut, given its DB ID
shortcutSec :: ShortcutId -> SettingsTree
shortcutSec sid = Section
    { secOpts = M.fromList
        [ ( "prefix"
          , mkOptionP (getf shortcutPrefix) (setf ShortcutPrefix) ""
          )
        , ( "before"
          , mkOptionP (getf shortcutBefore) (setf ShortcutBefore) ""
          )
        , ( "after"
          , mkOptionP (getf shortcutAfter) (setf ShortcutAfter) ""
          )
        , ( "channels"
          , mkOptionP
                (map (unChannel . shortcutChannelChannel . entityVal) <$>
                    selectList [ShortcutChannelShortcut ==. sid] []
                )
                (\ names -> do
                    olds <- map (shortcutChannelChannel . entityVal) <$>
                        selectList [ShortcutChannelShortcut ==. sid] []
                    let news = map Channel names
                        remove = filter (`notElem` news) olds
                        add = filter (`notElem` olds) news
                    deleteWhere [ShortcutChannelShortcut ==. sid, ShortcutChannelChannel <-. remove]
                    insertMany_ $ map (ShortcutChannel sid) add
                )
                []
          )
        ]
    , secSubs = M.empty
    }
    where
    err = "ERROR not found"
    getf f = maybe err f <$> get sid
    setf f v = update sid [f =. v]

-- | Add a new shortcut to settings and tree. Return whether success, i.e.
-- whether the shortcut didn't exist and indeed a new one has been created.
addShortcut :: ShortcutLabel -> Channel -> BotSession Bool
addShortcut label chan = runDB $ do
    ms <- getBy $ UniqueShortcut label
    case ms of
        Just _  -> return False
        Nothing -> do
            sid <- insert $ Shortcut label "PrEfIx" "http://BeFoRe.org/" "/AfTeR.html"
            insert_ $ ShortcutChannel sid chan
            let sec = shortcutSec sid
                ins = insertSub ["shortcuts", CI.foldedCase $ unShortcutLabel label] sec
            lift $ modifyState $ \ s -> s { bsSTree = ins $ bsSTree s }
            return True

-- | Remove a shortcut from settings and tree. Return whether success, i.e.
-- whether the shortcut did exist and indeed has been deleted.
deleteShortcut :: ShortcutLabel -> BotSession Bool
deleteShortcut label = runDB $ do
    ms <- getBy $ UniqueShortcut label
    case ms of
        Nothing              -> return False
        Just (Entity sid _s) -> do
            deleteWhere [ShortcutChannelShortcut ==. sid]
            delete sid
            let del = deleteSub ["shortcuts", CI.foldedCase $ unShortcutLabel label]
            lift $ modifyState $ \ s -> s { bsSTree = del $ bsSTree s }
            return True
